import time
from flask import Flask, request, jsonify
from flask_cors import CORS
import os
import pymysql
from pymysql import Error
import requests

# 导入数据库连接函数
from mysql import create_connection

# 创建一个后端应用
app = Flask(__name__, static_folder='static', static_url_path='/static')

# 配置CORS跨域
CORS(app, resources={r"/*": {
    "origins": "http://localhost:5173",  # 替换为前端实际域名
    "methods": ["GET", "POST", "OPTIONS"], 
    "allow_headers": ["Content-Type"],
    "supports_credentials": True
}})

# 增加文件大小限制到更大的值（例如50MB）
app.config['UPLOAD_FOLDER'] = './static'
app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024  # 增加到50MB

# 确保上传目录存在
if not os.path.exists(app.config['UPLOAD_FOLDER']):
    os.makedirs(app.config['UPLOAD_FOLDER'])

# DeepSeek API配置
# 在文件顶部添加额外的导入
import json
import logging

# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# 修改DeepSeek API配置部分
DEEPSEEK_API_KEY = 'sk-3ea26e21ddca4aa79c652974c324fa74'  # 请确保这里是您的有效API密钥
DEEPSEEK_API_URL = 'https://api.deepseek.com/chat/completions'

# 添加一个函数来获取指定主题下的最新几条消息
# 获取最近的聊天消息
# 修改get_recent_messages函数
def get_recent_messages(theme_id, limit=5):
    connection = None
    cursor = None
    try:
        connection = create_connection()
        if connection:
            cursor = connection.cursor(pymysql.cursors.DictCursor)  # 指定DictCursor
            sql = "SELECT * FROM chat_content WHERE theme_id = %s ORDER BY created_at DESC LIMIT %s"
            cursor.execute(sql, (theme_id, limit))
            result = cursor.fetchall()
            # 按时间升序返回
            return result[::-1]
        return []
    except Error as e:
        print(f"获取最近消息错误: {e}")
        return []
    finally:
        if cursor:
            cursor.close()
        if connection and connection.open:
            connection.close()

# 修改send_message函数
@app.route('/chat/send', methods=['POST'])
def send_message():
    try:
        data = request.json
        # 修改1：将 message 改为 content，匹配前端发送的参数
        user_message = data.get('content', '')
        theme_id = data.get('theme_id', 0)
        scene_id = data.get('scene_id', 0)  # 获取场景ID
        theme_name = data.get('theme_name', None)

        # 如果提供了场景ID但没有主题ID，使用场景ID作为主题ID的基础
        if scene_id > 0 and theme_id == 0:
            # 为场景创建一个默认主题
            scene_names = {
                1: '医疗咨询',
                2: '金融服务',
                3: '法律咨询',
                4: '教育辅导',
                5: '旅游规划'
            }
            theme_name = scene_names.get(scene_id, '未分类')
            # 生成一个唯一的主题ID，将场景ID作为前缀
            theme_id = scene_id * 10000  # 确保不同场景的主题ID不会冲突
            
            # 检查主题是否已存在于数据库，如果不存在则创建
            connection = create_connection()
            if connection:
                cursor = connection.cursor(pymysql.cursors.DictCursor)
                # 检查主题是否存在
                sql = "SELECT id FROM chat_themes WHERE id = %s"
                cursor.execute(sql, (theme_id,))
                result = cursor.fetchone()
                if not result:
                    # 创建新主题
                    sql = "INSERT INTO chat_themes (id, theme_name) VALUES (%s, %s)"
                    cursor.execute(sql, (theme_id, theme_name))
                    connection.commit()
                cursor.close()
                connection.close()

        # 如果没有主题名称且主题ID不为0，从数据库获取主题名称
        if not theme_name and theme_id > 0:
            connection = create_connection()
            if connection:
                cursor = connection.cursor(pymysql.cursors.DictCursor)  # 使用DictCursor
                sql = "SELECT theme_name FROM chat_themes WHERE id = %s"
                cursor.execute(sql, (theme_id,))
                result = cursor.fetchone()
                if result:
                    theme_name = result['theme_name']
                cursor.close()
                connection.close()

        # 如果主题ID为0，生成新主题
        if theme_id == 0:
            theme_name = generate_theme_with_deepseek(user_message)
            # 保存新主题到数据库
            connection = create_connection()
            if connection:
                cursor = connection.cursor()
                sql = "INSERT INTO chat_themes (theme_name) VALUES (%s)"
                cursor.execute(sql, (theme_name,))
                theme_id = cursor.lastrowid
                connection.commit()
                cursor.close()
                connection.close()

        # 保存用户消息
        save_chat_to_db('user', user_message, theme_id, theme_name)

        # 获取最近5条消息作为上下文
        recent_messages = get_recent_messages(theme_id)
        context = "\n".join([f"{msg['identity']}: {msg['content']}" for msg in recent_messages])

        # 调用DeepSeek API获取回复
        ai_response = get_deepseek_response(user_message, context)

        # 保存AI回复
        save_chat_to_db('ai', ai_response, theme_id, theme_name)

        return jsonify({
            'success': True,
            # 修改2：将 response 改为 ai_response，匹配前端期望的参数
            'ai_response': ai_response,
            'theme_id': theme_id,
            'theme_name': theme_name
        })
    except Exception as e:
        logger.error(f"处理消息时出错: {type(e).__name__} - {str(e)}")
        return jsonify({'error': '服务器内部错误'}), 500

# 添加获取DeepSeek回复的函数
# 修复get_deepseek_response函数
def get_deepseek_response(user_message, context_history):
    try:
        headers = {
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {DEEPSEEK_API_KEY}'
        }
        
        # 构建系统消息
        system_message = "你是一个智能助手，根据上下文历史回答用户问题。"
        logger.info(f"系统消息: {system_message}")
        
        # 构建发送给API的消息列表
        # 先添加系统消息
        all_messages = [{"role": "system", "content": system_message}]
        logger.info(f"初始消息列表: {all_messages}")
        
        # 如果有上下文历史，添加到消息列表
        if context_history:
            # 分割上下文历史为单独的消息
            history_lines = context_history.split('\n')
            for line in history_lines:
                if line.startswith('user: '):
                    all_messages.append({"role": "user", "content": line[6:]})
                elif line.startswith('ai: '):
                    all_messages.append({"role": "assistant", "content": line[3:]})
        
        # 添加当前用户消息
        all_messages.append({"role": "user", "content": user_message})
        logger.info(f"完整消息列表: {json.dumps(all_messages, ensure_ascii=False)}")
        
        data = {
            "model": "deepseek-chat",
            "messages": all_messages,
            "max_tokens": 500
        }
        
        logger.info(f"准备发送给DeepSeek的消息: {json.dumps(all_messages, ensure_ascii=False)}")
        
        response = requests.post(DEEPSEEK_API_URL, headers=headers, json=data, timeout=30)
        
        if response.status_code == 200:
            response_json = response.json()
            logger.info(f"DeepSeek API响应: {json.dumps(response_json, ensure_ascii=False)}")
            if "choices" in response_json and len(response_json["choices"]) > 0:
                return response_json["choices"][0]["message"]["content"].strip()
            else:
                logger.error(f"DeepSeek API返回无效数据: {response_json}")
                return "抱歉，我暂时无法回答这个问题。"
        else:
            logger.error(f"DeepSeek API请求失败，状态码: {response.status_code}")
            logger.error(f"DeepSeek API错误响应: {response.text}")
            return f"抱歉，API请求失败 (状态码: {response.status_code})"
    except requests.exceptions.Timeout:
        logger.error("DeepSeek API请求超时")
        return "抱歉，请求超时，请稍后重试。"
    except requests.exceptions.ConnectionError:
        logger.error("DeepSeek API连接错误")
        return "抱歉，网络连接失败，请检查您的网络设置。"
    except Exception as e:
        logger.error(f"获取AI回复时出错: {type(e).__name__} - {str(e)}")
        return f"抱歉，处理请求时发生错误: {type(e).__name__}"

# 自定义错误处理器 - 专门处理文件过大的错误
@app.errorhandler(413)
def request_entity_too_large(error):
    return jsonify({'error': '上传的文件过大，请选择小于50MB的文件'}), 413

# 初始化数据库表
# @app.before_first_request  # 注释或删除这行
def init_db():
    connection = create_connection()
    if connection:
        try:
            cursor = connection.cursor()
            
            # 注意：用户已手动创建数据库表，以下代码仅作为备用
            # 检查表是否存在，如果不存在才创建
            
            # 检查chat_content表是否存在
            cursor.execute("SHOW TABLES LIKE 'chat_content'")
            if not cursor.fetchone():
                cursor.execute('''
                CREATE TABLE chat_content (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    identity VARCHAR(255) NOT NULL,
                    content TEXT NOT NULL,
                    theme_id INT DEFAULT 0,
                    theme_name VARCHAR(255) DEFAULT NULL,
                    message_type VARCHAR(50) DEFAULT 'text',
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
                ''')
                print("创建chat_content表成功")
            else:
                print("chat_content表已存在")
            
            # 检查chat_themes表是否存在
            cursor.execute("SHOW TABLES LIKE 'chat_themes'")
            if not cursor.fetchone():
                cursor.execute('''
                CREATE TABLE chat_themes (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    theme_name VARCHAR(255) NOT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
                ''')
                print("创建chat_themes表成功")
            else:
                print("chat_themes表已存在")
            
            connection.commit()
            print("数据库表初始化完成")
        except Error as e:
            print(f"数据库初始化错误: {e}")
        finally:
            if connection and connection.open:
                cursor.close()
                connection.close()

# 使用DeepSeek生成主题
def generate_theme_with_deepseek(content):
    try:
        headers = {
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {DEEPSEEK_API_KEY}'
        }
        
        data = {
            "model": "deepseek-chat",
            "messages": [
                {"role": "system", "content": "请为以下聊天内容生成一个简短的主题，不超过10个中文字符"},
                {"role": "user", "content": content}
            ],
            "max_tokens": 50
        }
        
        response = requests.post(DEEPSEEK_API_URL, headers=headers, json=data)
        response_json = response.json()
        
        if response.status_code == 200 and "choices" in response_json:
            theme = response_json["choices"][0]["message"]["content"].strip()
            # 确保主题不超过10个字符
            if len(theme) > 10:
                theme = theme[:10]
            return theme
        else:
            print(f"DeepSeek API错误: {response_json}")
            return "未分类"
    except Exception as e:
        print(f"生成主题时出错: {e}")
        return "未分类"

# 保存聊天记录到数据库
def save_chat_to_db(identity, content, theme_id=0, theme_name=None, message_type='text', scene_id=None, conversation_id=None):
    # 添加非空验证
    if not content or content.strip() == '':
        print(f"拒绝保存空消息: identity={identity}")
        return False
    
    print(f"保存聊天记录: identity={identity}, content={content}, theme_id={theme_id}")
    connection = None
    cursor = None
    try:
        connection = create_connection()
        if connection:
            cursor = connection.cursor(pymysql.cursors.DictCursor)  # 指定DictCursor
            sql = '''INSERT INTO chat_content (identity, content, theme_id, theme_name, message_type, scene_id, conversation_id, created_at) 
                     VALUES (%s, %s, %s, %s, %s, %s, %s, CURRENT_TIMESTAMP)'''
            cursor.execute(sql, (identity, content, theme_id, theme_name, message_type, scene_id, conversation_id))
            connection.commit()
            return True
        return False
    except Error as e:
        print(f"保存聊天记录到数据库时出错: {e}")
        return False
    finally:
        # 确保关闭数据库连接
        if cursor:
            cursor.close()
        if connection:
            connection.close()

# 获取历史聊天记录
def get_chat_history(theme_id=None):
    connection = None
    cursor = None
    try:
        connection = create_connection()
        if connection:
            cursor = connection.cursor(pymysql.cursors.DictCursor)  # 使用DictCursor
            if theme_id is not None:
                sql = "SELECT * FROM chat_content WHERE theme_id = %s ORDER BY created_at ASC"
                cursor.execute(sql, (theme_id,))
            else:
                sql = "SELECT * FROM chat_content WHERE theme_id = 0 ORDER BY created_at ASC"
                cursor.execute(sql)
            result = cursor.fetchall()
            return result
        return []
    except Error as e:
        print(f"获取聊天记录错误: {e}")
        return []
    finally:
        if cursor:
            cursor.close()
        if connection and connection.open:
            connection.close()

# 检查文件类型
def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}

# 添加单数形式路由，指向复数形式路由的处理函数
@app.route('/chat/scene_history', methods=['GET'])
def scene_history():
    return scene_histories()
# 注册路由
@app.route('/user/chat', methods=['GET'])
def user():
    return jsonify({'text': 'hello world'})

@app.route('/chat/v1', methods=['GET'])
def chat1():
    return jsonify({'text': '123'})

@app.route('/chat/v2', methods=['POST'])
def chat2():
    return jsonify({'text': 'post数据'})

@app.route('/chat/v3', methods=['GET'])
def chat3():
    # 获取前端用GET方式传递的参数
    name = request.args["chat_text"]
    return jsonify({'text': name})

@app.route('/chat/v4', methods=['POST'])
def chat4():
    # 获取前端用post方式传递的参数
    name = request.json["chat_text"]
    return jsonify({'text': name})

@app.route('/chat/v5', methods=['POST'])
def chat5():
    try:
        # 获取前端用post方式传递的文件
        if 'face' not in request.files:
            return jsonify({'error': '没有文件部分'}), 400
        
        file = request.files["face"]
        if file.filename == '':
            return jsonify({'error': '没有选择文件'}), 400
        
        if file and allowed_file(file.filename):
            # 生成唯一的文件名
            filename = f"{int(time.time())}_{file.filename}"
            # 保存文件
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            # 返回正确的URL
            return jsonify({'url': f'http://localhost:8080/static/{filename}'})
        else:
            return jsonify({'error': '不支持的文件类型'}), 400
    except Exception as e:
        # 打印错误信息以便调试
        print(f"文件上传错误: {str(e)}")
        # 根据不同的错误类型返回不同的提示
        if '413' in str(e):
            return jsonify({'error': '上传的文件过大，请选择小于50MB的文件'}), 413
        return jsonify({'error': f'服务器错误: {str(e)}'}), 500

# 获取历史聊天记录API
@app.route('/chat/history', methods=['GET'])
def chat_history():
    try:
        theme_id = request.args.get('theme_id', type=int)
        
        # 获取历史记录
        history = get_chat_history(theme_id)
        
        # 格式化返回数据
        formatted_history = []
        for item in history:
            formatted_history.append({
                'id': item['id'],
                'identity': item['identity'],
                'content': item['content'],
                'theme_id': item['theme_id'],
                'theme_name': item['theme_name'],
                'message_type': item['message_type'],
                'created_at': item['created_at'].strftime('%Y-%m-%d %H:%M:%S')
            })
        
        return jsonify({
            'success': True,
            'history': formatted_history
        })
    except Exception as e:
        print(f"获取历史记录错误: {e}")
        return jsonify({'error': '服务器内部错误'}), 500

# 获取场景下的历史记录列表API
# 修改scene_histories函数
@app.route('/chat/scene_histories', methods=['GET'])
def scene_histories():
    try:
        scene_id = request.args.get('scene_id', type=int)
        if not scene_id:
            return jsonify({'error': '缺少场景ID'}), 400

        connection = create_connection()
        if connection:
            cursor = connection.cursor(pymysql.cursors.DictCursor)  # 使用DictCursor

            # 使用场景ID直接查询相关主题
            # 主题ID的格式为：场景ID * 10000 + 序号
            min_theme_id = scene_id * 10000
            max_theme_id = (scene_id + 1) * 10000

            sql = '''
            SELECT DISTINCT theme_id, theme_name, MAX(created_at) as last_message_time
            FROM chat_content 
            WHERE theme_id >= %s AND theme_id < %s
            GROUP BY theme_id, theme_name
            ORDER BY last_message_time DESC
            '''
            cursor.execute(sql, (min_theme_id, max_theme_id))
            result = cursor.fetchall()

            # 格式化返回数据
            formatted_histories = []
            for item in result:
                formatted_histories.append({
                    'theme_id': item['theme_id'],
                    'theme_name': item['theme_name'] if item['theme_name'] else '未命名对话',
                    'last_message_time': item['last_message_time'].strftime('%Y-%m-%d %H:%M:%S')
                })

            cursor.close()
            connection.close()

            return jsonify({
                'success': True,
                'histories': formatted_histories
            })
        else:
            return jsonify({
                'success': True,
                'histories': []
            })
    except Exception as e:
        print(f"获取场景历史记录错误: {e}")
        return jsonify({'error': '服务器内部错误'}), 500

# 在应用启动前添加stream_send路由
@app.route('/chat/stream_send', methods=['POST', 'OPTIONS'])
def stream_send():
    # 处理OPTIONS请求用于CORS预检
    if request.method == 'OPTIONS':
        response = jsonify({})
        response.headers.add('Access-Control-Allow-Origin', 'http://localhost:5173')  # 替换为前端实际域名
        response.headers.add('Access-Control-Allow-Headers', 'Content-Type')
        response.headers.add('Access-Control-Allow-Methods', 'POST, OPTIONS')
        response.headers.add('Access-Control-Allow-Credentials', 'true')
        return response

    try:
        data = request.json
        user_message = data.get('message', '')
        theme_id = data.get('theme_id', 0)
        scene_id = data.get('scene_id', 0)
        theme_name = data.get('theme_name', None)

        # 保存用户消息
        save_chat_to_db('user', user_message, theme_id, theme_name)

        # 获取最近5条消息作为上下文
        recent_messages = get_recent_messages(theme_id)
        context = "\n".join([f"{msg['identity']}: {msg['content']}" for msg in recent_messages])

        # 返回流式响应
        def generate():
            # 调用DeepSeek API获取流式回复
            headers = {
                'Content-Type': 'application/json',
                'Authorization': f'Bearer {DEEPSEEK_API_KEY}'
            }

            system_message = "你是一个智能助手，根据上下文历史回答用户问题。"
            all_messages = [{"role": "system", "content": system_message}]

            if context:
                history_lines = context.split('\n')
                for line in history_lines:
                    if line.startswith('user: '):
                        all_messages.append({"role": "user", "content": line[6:]})
                    elif line.startswith('ai: '):
                        all_messages.append({"role": "assistant", "content": line[3:]})

            all_messages.append({"role": "user", "content": user_message})

            data = {
                "model": "deepseek-chat",
                "messages": all_messages,
                "max_tokens": 500,
                "stream": True
            }

            response = requests.post(DEEPSEEK_API_URL, headers=headers, json=data, stream=True)

            full_response = ""
            for chunk in response.iter_content(chunk_size=None):
                if chunk:
                    chunk_str = chunk.decode('utf-8')
                    # 处理SSE格式
                    for line in chunk_str.split('\n'):
                        line = line.strip()
                        if line.startswith('data: '):
                            data_part = line[6:]
                            if data_part == '[DONE]':
                                # 保存完整回复
                                save_chat_to_db('ai', full_response, theme_id, theme_name)
                                # 使用json.dumps正确处理JSON格式
                                yield f"data: {json.dumps({'done': True})}\n\n"
                            else:
                                try:
                                    json_data = json.loads(data_part)
                                    if 'choices' in json_data and len(json_data['choices']) > 0:
                                        delta = json_data['choices'][0].get('delta', {})
                                        content = delta.get('content', '')
                                        if content:
                                            full_response += content
                                            # 确保内容被正确转义
                                            yield f"data: {json.dumps({'chunk': content}, ensure_ascii=False)}\n\n"
                                except json.JSONDecodeError:
                                    pass

        response = app.response_class(generate(), mimetype='text/event-stream')
        response.headers.add('Access-Control-Allow-Origin', 'http://localhost:5173')  # 替换为前端实际域名
        response.headers.add('Access-Control-Allow-Credentials', 'true')
        return response

    except Exception as e:
        logger.error(f"处理流式消息时出错: {type(e).__name__} - {str(e)}")
        # 添加更多调试信息
        import traceback
        logger.error(f"错误堆栈: {traceback.format_exc()}")
        return jsonify({'error': '服务器内部错误', 'details': str(e)}), 500

# 在应用启动时手动调用init_db()
with app.app_context():
    init_db()

# 启动应用
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, debug=True)


